#include "Thread.h"
#include <process.h>

namespace GPUCC
{
	namespace CPU
	{
		Thread::Thread(std::shared_ptr<IThreadable> Logic) : m_Thread(NULL), m_IsRunning(false), m_ThreadId(0), m_Logic(Logic)
		{
		}

		Thread::~Thread()
		{
			if (this->m_Thread != NULL)
			{
				if (this->m_IsRunning)
				{
					this->StopAndWait();
				}

				CloseHandle(this->m_Thread);
				m_Thread = NULL;
			}
		}

		bool Thread::Start(std::shared_ptr<IThreadable> Logic)
		{
			bool Started = false;

			if (m_IsRunning)
			{
				return (Started);
			}

			if (Logic.get() != NULL)
			{
				this->m_Logic = Logic;
			}

			if (this->m_Logic.get() == NULL)
			{
				return (Started);
			}

			this->m_Thread = (HANDLE)_beginthreadex(NULL, 0, Thread::ThreadFunc, this, 0, &this->m_ThreadId);

			if (this->m_Thread != NULL)
			{			
				Started = true;
			}

			return (Started);
		}

		void Thread::Join(unsigned int Timeout)
		{
			if (this->m_Thread != NULL)
			{
				WaitForSingleObject(this->m_Thread, Timeout);
			}
		}

		void Thread::Stop()
		{
			if (this->m_Thread != NULL)
			{
				this->m_Logic->Stop();
			}
		}

		void Thread::StopAndWait()
		{
			if (this->m_Thread != NULL)
			{
				this->m_Logic->Stop();

				this->Join();
			}
		}

		bool Thread::IsRunning()
		{
			return (this->m_IsRunning);
		}

		unsigned int Thread::ThreadId()
		{
			return (this->m_ThreadId);
		}

		unsigned int __stdcall Thread::ThreadFunc(void* Arguments)
		{
			Thread* threadInstance = static_cast<Thread*>(Arguments);
			
			threadInstance->m_IsRunning = true;

			threadInstance->m_Logic->Run();

			threadInstance->m_IsRunning = false;

			return (0);
		}
	}
}